package com.yiduo.outpost.core.web.argument;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.Data;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 条件查询实体
 * {@code /<service>/<resources>/collect/filter?filtering=[<FilteringParam>]}
 *
 * @author yanwen
 */
@Data
public class FilteringParam {

    /**
     * 列名
     */
    private String field;

    /**
     * 谓词
     */
    private Operator operator;

    /**
     * 条件查询值
     */
    private Object[] values;

    /**
     * 逻辑条件
     */
    private Logic logic = Logic.AND;

    /**
     * 条件查询值类型转换
     */
    private FilteringParamConverterType converterType;

    public static <T> QueryWrapper<T> toQueryWrapper(List<FilteringParam> params) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        if (params != null && !params.isEmpty()) {
            Map<Logic, List<FilteringParam>> filteringParamMap = params.stream()
                // 过滤空值
                .filter(p -> p.getField() != null && p.getOperator().isValid(p.getValues()))
                // 转换类型
                .peek(p -> {
                    if (p.getConverterType() != null) {
                        p.setValues(Arrays.stream(p.getValues())
                            .map(a -> p.getConverterType().getConverter().convert(a.toString()))
                            .toArray());
                    }
                })
                .collect(Collectors.groupingBy(FilteringParam::getLogic));

            List<FilteringParam> andFilteringPrams = filteringParamMap.get(Logic.AND);
            List<FilteringParam> orFilteringPrams = filteringParamMap.get(Logic.OR);
            boolean andFilteringParamsExists = andFilteringPrams != null && !andFilteringPrams.isEmpty();
            boolean orFilteringParamsExists = orFilteringPrams != null && !orFilteringPrams.isEmpty();

            // and条件拼接
            if (andFilteringParamsExists) {
                andFilteringPrams.forEach(p -> p.getOperator().accept(queryWrapper, p));
            }
            // or条件拼接
            if (orFilteringParamsExists) {
                if (andFilteringParamsExists) {
                    queryWrapper.and(qw -> orFilteringPrams.forEach(p -> {
                        qw.or();
                        p.getOperator().accept(qw, p);
                    }));
                } else {
                    orFilteringPrams.forEach(p -> {
                        queryWrapper.or();
                        p.getOperator().accept(queryWrapper, p);
                    });
                }
            }
        }
        return queryWrapper;
    }

}
